﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace TimeZoneTest.ViewModel.Base
{
   using System.Collections.Generic;
   using System.Collections.ObjectModel;
   using System.ComponentModel;
   using System.Linq.Expressions;
   using System.Reflection;

   

   /// <summary>
   ///     Base class for items that implement property changed
   /// </summary>
   public abstract class BaseNotify : INotifyPropertyChanged
   {
      

      /// <summary>
      /// Raised when a property on this object has a new value.
      /// </summary>
      public event PropertyChangedEventHandler PropertyChanged;

      /// <summary>
      /// Raises this object's PropertyChanged event.
      /// </summary>
      /// <param name="propertyName">The property that has a new value.</param>
      protected virtual void RaisePropertyChanged(string propertyName)
      {
         var handler = PropertyChanged;
         if (handler != null)
         {
            handler(this, new PropertyChangedEventArgs(propertyName));
         }

        
      }

      /// <summary>
      /// Raises this object's PropertyChanged event for each of the properties.
      /// </summary>
      /// <param name="propertyNames">The properties that have a new value.</param>
      protected void RaisePropertyChanged(params string[] propertyNames)
      {
         foreach (var name in propertyNames)
         {
            RaisePropertyChanged(name);
         }
      }

      /// <summary>
      /// Raises this object's PropertyChanged event.
      /// </summary>
      /// <typeparam name="T">The type of the property that has a new value</typeparam>
      /// <param name="propertyExpression">A Lambda expression representing the property that has a new value.</param>
      protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
      {
         var propertyName = ExtractPropertyName(propertyExpression);
         RaisePropertyChanged(propertyName);
      }

      protected string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
      {
         if (propertyExpression == null)
         {
            throw new ArgumentNullException("propertyExpression");
         }

         var memberExpression = propertyExpression.Body as MemberExpression;
         if (memberExpression == null)
         {
            throw new ArgumentException("The expression is not a member access expression.", "propertyExpression");
         }

         var property = memberExpression.Member as PropertyInfo;
         if (property == null)
         {
            throw new ArgumentException("The member access expression does not access a property.", "propertyExpression");
         }

         if (!property.DeclaringType.IsAssignableFrom(GetType()))
         {
            throw new ArgumentException("The referenced property belongs to a different type.", "propertyExpression");
         }

         var getMethod = property.GetGetMethod(true);
         if (getMethod == null)
         {
            // this shouldn't happen - the expression would reject the property before reaching this far
            throw new ArgumentException("The referenced property does not have a get method.", "propertyExpression");
         }

         if (getMethod.IsStatic)
         {
            throw new ArgumentException("The referenced property is a static property.", "propertyExpression");
         }

         return memberExpression.Member.Name;
      }


   }
}
